import type {OptinoCallback} from "@/util/calHash";

/**
 * 加密类型
 */
enum EncryptType {
    NO,//不加密
    MD5,
    SHA256,
    SHA512
}

/**
 * 文件上传状态
 */
enum FileStatus {
    CHECK,//文件校验
    WAITING,//排队等候上传
    UPLOADING,//上传中
    PAUSE,//暂停
    RESUME,//继续
    MERGE,//合并文件中
    SUCCESS,//上传成功
    FAIL,//上传失败

}

interface UFile extends File {
    hasher?: Object;
    uniqueIdentifier?: string;//唯一标识
    totalChunks: number;//总的片数
    status: FileStatus;
    chunkSize: number;//分片大小
    child?: UFile[];
    // currentChunkSize: number;//当前分片大小
    nextChunkNumber: number;//下次应该上传第几片
}

class UDir implements UFile {
    chunkSize = Number.MAX_VALUE;
    readonly lastModified = 0;
    readonly name = "";
    readonly size = 0;
    status = FileStatus.WAITING;
    totalChunks = 1;
    readonly type = "directory";
    readonly webkitRelativePath = "";
    child: UFile[] = [];
    hasher = {};
    uniqueIdentifier = "";
    nextChunkNumber = 0;

    arrayBuffer(): Promise<ArrayBuffer> {
        return Promise.resolve(new ArrayBuffer(0));
    }

    slice(start?: number, end?: number, contentType?: string): Blob {
        return new Blob();
    }

    stream(): ReadableStream<Uint8Array> {
        return new ReadableStream<Uint8Array>();
    }

    text(): Promise<string> {
        return Promise.resolve("");
    }

    push(uFile: UFile) {
        return this.child.push(uFile);
    }

}

interface Chunk {
    uniqueIdentifier?: string;//唯一标识
    totalChunks?: number;//总的片数
    chunkSize?: number;//分片大小
    currentSize?: number;//当前分片大小
    chunk?: number;//第几片
}


interface Options {
    addFile?: Function;
    addFiles?: Function;
    thread?: number;//线程数
    chunkSize?: number; //Number.MAX_VALUE;//分片大小，为空则不分片
    immediate?: boolean;//是否立即上传
    // preview?: Function; //预览回调函数，自定义预览方式
    encryptType?: EncryptType;//加密配置
    target: string;
    testTarget: string;
    calHashCallback?: OptinoCallback;
}

class UF {

}

interface Set<T> {
    add(value: T): this;

    clear(): void;

    delete(value: T): boolean;

    has(value: T): boolean;

    size: number;

}

class FileSet implements Set<UFile> {
    private _size: number = 0;
    private map = new Map<string, UFile>();

    get size(): number {
        // return this._size;
        return this.map.size;
    }

    add(item: UFile): this {
        if (!this.has(item)) {
            this.map.set(this.getUniqueIdentifier(item), item);
            // this._size++
            this._size = this.map.size
        }
        return this;
    }

    clear(): void {
        this.map = new Map<string, UFile>();
        // this._size = 0;
        this._size = this.map.size
    }

    delete(item: UFile): boolean {
        const flag = this.map.delete(this.getUniqueIdentifier(item));
        if (flag) {
            // this._size--
        }
        this._size = this.map.size
        return flag;
    }

    has(item: UFile): boolean {
        return this.map.has(this.getUniqueIdentifier(item))
    }

    getUniqueIdentifier(item: UFile): string {
        return item.name + item.size + item.lastModified + item.webkitRelativePath + item.child?.length;
    }

    getMap(): Map<string, UFile> {
        return this.map;
    }

    forEach(callback: (uFile: UFile) => void, thisArg?: any): void {
        return this.getMap().forEach((uFile: UFile, key: string) => {
            callback(uFile)
        }, thisArg);
    }

    getUploadFile() {
        for (let uFile of this.map.values()) {
            if ((uFile.status === FileStatus.WAITING || uFile.status === FileStatus.UPLOADING) && uFile.nextChunkNumber <= uFile.totalChunks) {
                return uFile;
            }
        }
        return null;
    }
}
interface Param{
    uniqueIdentifier?: string;//唯一标识
    totalChunks: number;//总的片数
    chunkSize: number;//分片大小
    currentChunkSize: number;//当前分片大小
    currentChunkNumber: number;//当前分片编号
}

export {EncryptType, FileStatus, UF, FileSet, UDir}
export type {UFile, Chunk, Options,Param}